Skip to content

Fix #11730: array_filter with assert-if-true callable marks all keys optional#5097

Open
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-wrykofq
Open

Fix #11730: array_filter with assert-if-true callable marks all keys optional#5097
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-wrykofq

Conversation

@phpstan-bot
Copy link
Collaborator

Summary

When using array_filter with a callable annotated with @phpstan-assert-if-true, all keys in the resulting array were incorrectly marked as optional, even when the input elements already satisfied the asserted type. A callable with a conditional return type (@return ($value is Foo ? true : false)) correctly preserved keys as non-optional.

Changes

  • Modified processKeyAndItemType() in src/Type/Php/ArrayFilterFunctionReturnTypeHelper.php to check the falsey branch when the boolean result is not definitely true
  • If filterByFalseyValue makes the item or key variable type NeverType, the callback cannot return false for the given input type, so the key is not marked optional

Root cause

The processKeyAndItemType() method determined key optionality solely based on whether the callback's return type was definitely true ($booleanResult->isTrue()->yes()). For @phpstan-assert-if-true callbacks, the return type is bool (not conditionally true), so keys were always marked optional regardless of the input type.

The fix adds a secondary check: when the return type isn't definitely true, it evaluates the falsey branch. If filtering by the falsey value produces NeverType for the item or key variable, it means the false branch is impossible for this input type (e.g., passing Foo through a callback that asserts Foo on the true branch means the false branch would require !Foo, which is never). In that case, the key is correctly kept as non-optional.

Test

Added tests/PHPStan/Analyser/nsrt/bug-11730.php — an NSRT test that verifies array_filter with both a conditional return type callback and an @phpstan-assert-if-true callback produce array{Foo, Foo} (non-optional keys) when filtering an array of Foo elements.

Fixes phpstan/phpstan#11730

- When array_filter callback has @phpstan-assert-if-true, check the falsey branch
  to determine if the callback can actually return false for the given input type
- If filtering by falsey value makes the item/key type NeverType, the false branch
  is impossible, so the key should not be marked optional
- New regression test in tests/PHPStan/Analyser/nsrt/bug-11730.php

Closes phpstan/phpstan#11730
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant